package com.robertlundberg.chess;

import java.util.List;

/**
 * class Board
 * 
 * Defines the chess board and the position it holds with required move history and other game related properties. 
 * Methods to update and visualize the board are represented as well.
 * 
 * @author Robert Lundberg
 */
public class Board {
	int[] Squares = new int[128];
	Color SideToMove;
	Piece[] PieceList = new Piece[32];
	Piece[] WhitePieces = new Piece[16];
	Piece[] BlackPieces = new Piece[16];
	static final String[] SquareNameLookUp = new String[128];
	static final Color[] SquareColorLookUp = new Color[128];
	static Boolean WhiteKingSideCastle = true;
	static Boolean WhiteQueenSideCastle = true;
	static Boolean BlackKingSideCastle = true;
	static Boolean BlackQueenSideCastle = true;
	int[] History = new int[1024];
	Piece[] CaptureHistory = new Piece[1024];
	int HistoryIndex = 0;

	public static enum Color
	{
		Black,White;
	}
	public Board()
	{			
		initBoardToStartPosition();		
		SideToMove = Color.White;
	}
	//Initialization	
	private void initBoardToStartPosition()
	{	
		initPiecesToStartPosition();
		for(int i = 0;i < Squares.length;i++)
		{
			Squares[i] = -1;
		}
		for(int i = 0;i < PieceList.length;i++)
		{
			Squares[PieceList[i]._position] = i;
		}	
		
	}	
	private void initPiecesToStartPosition()
	{
		//White Pieces
		WhitePieces[0] = new Piece.Knight(Piece.PieceType.WhiteKnight,1,Piece.PieceValues.Knight.getValue());
		WhitePieces[1] = new Piece.Knight(Piece.PieceType.WhiteKnight,6,Piece.PieceValues.Knight.getValue());
		WhitePieces[2] = new Piece.Bishop(Piece.PieceType.WhiteBishop,5,Piece.PieceValues.Bishop.getValue());
		WhitePieces[3] = new Piece.Bishop(Piece.PieceType.WhiteBishop,2,Piece.PieceValues.Bishop.getValue());
		WhitePieces[4] = new Piece.Rook(Piece.PieceType.WhiteRook,0,Piece.PieceValues.Rook.getValue());
		WhitePieces[5] = new Piece.Rook(Piece.PieceType.WhiteRook,7,Piece.PieceValues.Rook.getValue());
		WhitePieces[6] = new Piece.King(Piece.PieceType.WhiteKing,4,Piece.PieceValues.King.getValue());
		WhitePieces[7] = new Piece.Queen(Piece.PieceType.WhiteQueen,3,Piece.PieceValues.Queen.getValue());
		WhitePieces[8] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,16,Piece.PieceValues.Pawn.getValue());
		WhitePieces[9] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,17,Piece.PieceValues.Pawn.getValue());
		WhitePieces[10] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,18,Piece.PieceValues.Pawn.getValue());
		WhitePieces[11] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,19,Piece.PieceValues.Pawn.getValue());
		WhitePieces[12] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,20,Piece.PieceValues.Pawn.getValue());
		WhitePieces[13] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,21,Piece.PieceValues.Pawn.getValue());
		WhitePieces[14] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,22,Piece.PieceValues.Pawn.getValue());
		WhitePieces[15] = new Piece.WhitePawn(Piece.PieceType.WhitePawn,23,Piece.PieceValues.Pawn.getValue());		
		
		System.arraycopy(WhitePieces, 0, PieceList, 0, 16);		
		
		//Black Pieces	
		BlackPieces[0] = new Piece.Knight(Piece.PieceType.BlackKnight,113,Piece.PieceValues.Knight.getValue());
		BlackPieces[1] = new Piece.Knight(Piece.PieceType.BlackKnight,118,Piece.PieceValues.Knight.getValue());
		BlackPieces[2] = new Piece.Bishop(Piece.PieceType.BlackBishop,114,Piece.PieceValues.Bishop.getValue());
		BlackPieces[3] = new Piece.Bishop(Piece.PieceType.BlackBishop,117,Piece.PieceValues.Bishop.getValue());
		BlackPieces[4] = new Piece.Rook(Piece.PieceType.BlackRook,112,Piece.PieceValues.Rook.getValue());
		BlackPieces[5] = new Piece.Rook(Piece.PieceType.BlackRook,119,Piece.PieceValues.Rook.getValue());
		BlackPieces[6] = new Piece.King(Piece.PieceType.BlackKing,116,Piece.PieceValues.King.getValue());
		BlackPieces[7] = new Piece.Queen(Piece.PieceType.BlackQueen,115,Piece.PieceValues.Queen.getValue());
		BlackPieces[8] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,32,Piece.PieceValues.Pawn.getValue());
		BlackPieces[9] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,97,Piece.PieceValues.Pawn.getValue());
		BlackPieces[10] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,98,Piece.PieceValues.Pawn.getValue());
		BlackPieces[11] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,99,Piece.PieceValues.Pawn.getValue());
		BlackPieces[12] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,100,Piece.PieceValues.Pawn.getValue());
		BlackPieces[13] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,101,Piece.PieceValues.Pawn.getValue());
		BlackPieces[14] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,102,Piece.PieceValues.Pawn.getValue());
		BlackPieces[15] = new Piece.BlackPawn(Piece.PieceType.BlackPawn,103,Piece.PieceValues.Pawn.getValue());		
				
		System.arraycopy(BlackPieces, 0, PieceList, 16, 16);
	}
	
	//Visualization
	protected void PrintBoardWPieceListPositions()
	{			
		for(int rank = 7;rank >= 0;rank--)
		{
			for(int file = 0;file < 8;file++)
			{
				System.out.printf("(%d)\t",Squares[(rank << 4) +file]);				
			}	
			System.out.printf("- %d\t\n",rank+1);
		}
		for(int i = 0;i < 8;i++)
		{
			System.out.printf(" | \t");				
		}	
		System.out.println("");
		System.out.printf(" A \t");	
		System.out.printf(" B \t");
		System.out.printf(" C \t");
		System.out.printf(" D \t");
		System.out.printf(" E \t");
		System.out.printf(" F \t");
		System.out.printf(" G \t");
		System.out.printf(" H \t");			
	}
	protected void PrintBoardWPieceValues()
	{	
		System.out.println("");
		for(int rank = 7;rank >= 0;rank--)
		{
			for(int file = 0;file < 8;file++)
			{
				if(Squares[(rank << 4) +file] != -1)
					System.out.printf("(%d)\t",PieceList[Squares[(rank << 4) +file]]._type.getValue());
				else
					System.out.printf("(0)\t");					
			}	
			System.out.printf("- %d\t\n",rank+1);
		}
		for(int i = 0;i < 8;i++)
		{
			System.out.printf(" | \t");				
		}	
		System.out.println("");
		System.out.printf(" A \t");	
		System.out.printf(" B \t");
		System.out.printf(" C \t");
		System.out.printf(" D \t");
		System.out.printf(" E \t");
		System.out.printf(" F \t");
		System.out.printf(" G \t");
		System.out.printf(" H \t");			
	}
	protected void PrintSquares()
	{
		System.out.println("");
		for(int i = 0;i < Squares.length;i++)
		{
			System.out.printf("(%d) ",Squares[i]);
		}	
	}
	protected void SetupBoardFromFEN(String newFEN)
	{
		
	}
	protected void PrintPieceListPositions()
	{
		System.out.println("");
		for(int i = 0;i<PieceList.length;i++)
		{
			System.out.printf("%d ", PieceList[i]._position);			
		}		
	}
	protected boolean SquareHasWhitePiece(int position)
	{
		if(Squares[position] > -1)
			return PieceList[Squares[position]]._type.getValue() > 0 ? true : false;
		else
			return false;				
	}
	protected boolean SquareHasBlackPiece(int position)
	{
		if(Squares[position] > -1)
			return PieceList[Squares[position]]._type.getValue() < 0 ? true : false;
		else
			return false;				
	}
	protected boolean SquareIsEmpty(int position)
	{
		return Squares[position] == -1 ? true : false;
	}
	protected int FindPieceListIndexByPos(int pos,Piece[] list)
	{
		for(int i=0;i < list.length;i++)
		{
			if(list[i]._position == pos)
				return i;			
		}		
		return -1; //If we get this something is corrupt in the piecelist.
	}
	protected int FindEmptyPieceListIndex(Piece[] list) 
	{
		for(int i=0;i < list.length;i++)
		{
			if(list[i] == null )
				return i;			
		}		
		return -1;
	}
	protected int MakeMove(int move)
	{
		History[++HistoryIndex] = move;
		int from = Move.GetFromSquare(move);
		int to = Move.GetToSquare(move);
		
		if(this.SideToMove == Board.Color.White)
		{		
			if(SquareIsEmpty(to))
			{				
				Squares[to] = Squares[from];
				Squares[from] = -1;				
			}
			else //Move is a capture
			{
				int listindex = FindPieceListIndexByPos(to,BlackPieces);
				CaptureHistory[HistoryIndex] = BlackPieces[listindex];
				BlackPieces[listindex] = null;
				PieceList[Squares[to]] = null;
				
				Squares[to] = Squares[from];
				Squares[from] = -1;	
			}			
			WhitePieces[Move.GetPieceListIndex(move)]._position = to;
			PieceList[Squares[to]]._position = to;
			
			this.SideToMove = Board.Color.Black;
		}
		else //Black to move
		{
			if(SquareIsEmpty(to))
			{
				Squares[to] = Squares[from];
				Squares[from] = -1;		
			}
			else //Move is a capture
			{
				int listindex = FindPieceListIndexByPos(to,WhitePieces);
				CaptureHistory[HistoryIndex] = WhitePieces[listindex];
				WhitePieces[listindex] = null;
				PieceList[Squares[to]] = null;
				
				Squares[to] = Squares[from];
				Squares[from] = -1;	
			}
				
			BlackPieces[Move.GetPieceListIndex(move)]._position = to;
			PieceList[Squares[to]]._position = to;
			
			this.SideToMove = Board.Color.White;
		}		
		
		return HistoryIndex;
	}
	protected int UnMakeMove()
	{		
		int move = History[HistoryIndex];		
		int from = Move.GetFromSquare(move);
		int to = Move.GetToSquare(move);
		
		if(this.SideToMove == Board.Color.White)//We must unmake a black move
		{
			if(CaptureHistory[HistoryIndex] == null)
			{
				Squares[from] = Squares[to];
				Squares[to] = -1;						
				
			}
			else //Must restore a captured piece (a white piece)
			{
				int wlistindex = FindEmptyPieceListIndex(WhitePieces);
				int listindex = FindEmptyPieceListIndex(PieceList);
				WhitePieces[wlistindex] = CaptureHistory[HistoryIndex];
				PieceList[listindex] = CaptureHistory[HistoryIndex];
			
				Squares[from] = Move.GetPieceListIndex(move);
				Squares[to] = listindex;	
			}			
			BlackPieces[Move.GetPieceListIndex(move)]._position = from;
			PieceList[Squares[from]]._position = from;
			this.SideToMove = Board.Color.Black;
		}
		else //We must unmake a white move
		{
			if(CaptureHistory[HistoryIndex] == null)
			{
				Squares[from] = Squares[to];
				Squares[to] = -1;					
				
			}
			else //Must restore a captured piece (a black piece)
			{
				int blistindex = FindEmptyPieceListIndex(BlackPieces);
				int listindex = FindEmptyPieceListIndex(PieceList);
				BlackPieces[blistindex] = CaptureHistory[HistoryIndex];
				PieceList[listindex] = CaptureHistory[HistoryIndex];
				
				Squares[from] = Move.GetPieceListIndex(move);
				Squares[to] = listindex;	
			}			
			WhitePieces[Move.GetPieceListIndex(move)]._position = from;
			PieceList[Squares[from]]._position = from;
			this.SideToMove = Board.Color.White;
		}
		
		return --HistoryIndex;
	}
	protected void printList(List L)
	{
		
	}
	protected void printHistory()
	{
		
	}

}
